<?php
/**
 * Classe d'analyse rapide des champs Accept-* envoyés
 *
 * Cette classe analyse pour l'instant uniquement l'entête Accept: et dans le 
 * futur, les autres entêtes de ce type, exemple :
 *
 * Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,
 * text/plain;q=0.8,image/png,* / *;q=0.5
 * 
 * La RFC n'est pas 100% supportée, en particulier en ce qui concerne les
 * types MIME, le champs parameter du mediarange entre en conflit avec 
 * accept-params. A priori ce n'est pas gênant, les navigateurs web
 * n'utilisant pas cette possibilité offerte par la RFC.
 * 
 * Pour l'entête Accept-Charset, la RFC est 100% supportée.
 * 
 * TODO Ajouter le support de Accept-Encoding puis Accept-Language
 *
 * Implémenté en singleton - Classe PHP5 - Encodage UTF-8
 *
 * @package    HTTP
 * @author     Philippe MARASSE <philippe.marasse@vienneinfo.org>
 * @licence    http://www.opensource.org/licenses/gpl-license.php
 * @version    $Id: class.dirapHttpAccept.inc.php,v 1.4 2007/06/20 10:25:06 philippe Exp $
 */

class dirapHttpAccept {
    
    /**
     * Constante texte sélectionnant tous les types MIME : * / * 
     */
    const MIME_ALL = '*/*';
    
    /**
     * Constante texte sélectionnant le type MIME HTML
     */
    const MIME_HTML = 'text/html';
    
    /**
     * Constante texte sélectionnant le vrai type MIME XHTML (RFC 3236)
     * 
     * Type qui devrait être envoyé par un navigateur supportant bien
     * le XHTML.
     */
    const MIME_XHTML = 'application/xhtml+xml';
    
    /**
     * Constante texte sélectionnant le type MIME text/xml (RFC 3023)
     * 
     * Type utilisé si le document XML peut être lu par l'utilisateur. 
     * Si le navigateur ne supporte pas ce type, il pourra l'afficher 
     * comme un text/plain.
     */
    const MIME_TEXT_XML = 'text/xml';

    /**
     * Constante texte sélectionnant le type MIME application/xml (RFC 3023)
     * 
     * Type utilisé si le document XML n'est pas lisible par l'utilisateur
     */
    const MIME_APP_XML = 'application/xml';
    
    /**
     * Constantes texte sélectionannt tous les jeux de caractères : *
     */
    const CHARSET_ALL = '*';
    
    /**
     * Constante texte de jeu de caractère LATIN1 (utilisé en europe occidentale)
     */
    const CHARSET_LATIN1  = 'iso-8859-1';
    
    /**
     * Constante texte de jeu de caractère UNICODE 8 bits
     */
    const CHARSET_UNICODE = 'utf-8';
    
    /**
     * @access private
     * @var array Hash des types MIME acceptés
     */
    private $mime = array();

    /**
     * @var array Hash des jeux de caractères supportés
     * @access private
     */
    private $charset = array();
    
    /**
     * @var dirapHttpAccept Instance unique
     * @access private
     */
    private static $instance;

    /**
     * Constructeur privé - utiliser getInstance pour récupérer l'instance courante
     *
     * Effectue l'analyse des entêtes HTTP
     *
     * @access private
     */
    private function __construct() {
        // Gère l'entête Accept: constitué de champs séparés par des ','
        if (isset($_SERVER['HTTP_ACCEPT'])) {
            $lc_typeq = split(',',strtolower($_SERVER['HTTP_ACCEPT']));
            foreach ($lc_typeq as $lc_type) {
                if (preg_match('@^\s*(\S+)\s*;\s*q\s*=\s*(\S+)@',$lc_type,$lc_params)) {
                    // La qualité est transmise donc on l'enregistre
                    $this->mime[$lc_params[1]]=floatval($lc_params[2]);
                } else {
                    // La qualité n'est pas transmise : 1 par défaut
                    $this->mime[trim($lc_type)]=1.0;
                }
            }
        }
        
        // Gère l'entête Accept-charset: constitué de champs séparés par des ','
        if (isset($_SERVER['HTTP_ACCEPT_CHARSET'])) {
            $lc_charsetq = split(',',strtolower($_SERVER['HTTP_ACCEPT_CHARSET']));
            foreach ($lc_charsetq as $lc_charset) {
                if (preg_match('@^\s*(\S+)\s*;\s*q\s*=\s*(\S+)@',$lc_charset,$lc_params)) {
                    // La qualité est transmise donc on l'enregistre
                    $this->charset[$lc_params[1]]=floatval($lc_params[2]);
                } else {
                    // La qualité n'est pas transmise : 1 par défaut
                    $this->charset[trim($lc_charset)]=1.0;
                }
            }
        }
    }

    /**
     * Récupération de l'instance courante
     *
     * @access public
     * @return dirapHttpAccept instance à utiliser
     */
    public static function getInstance() {
        if (! isset(self::$instance)) {
            self::$instance = new dirapHttpAccept();
        }
        return self::$instance;
    }

    /**
     * Récupère la liste des types MIME acceptés
     *
     * @access public
     * @return array
     */
    public function getMimeAccept() {
        return $this->mime;
    }

    /**
     * Vérifie si un type mime fourni est supporté
     *
     * @param string $in_mime Type mime recherché
     * @return integer qualité (1 <=> préféré, 0 <=> inconnu)
     */
    public function getMimeQuality($in_mime) {
        $lc_mime = strtolower($in_mime);
        if (array_key_exists($lc_mime, $this->mime)) {
            return $this->mime[$lc_mime];
        } elseif (array_key_exists(self::MIME_ALL,$this->mime)) {
            return $this->mime[self::MIME_ALL];
        } else {
            return 0.0;
        }
    }

    /**
     * Récupère la liste des jeux de caractères acceptés
     *
     * @access public
     * @return array
     */
    public function getCharsetAccept() {
        return $this->charset;
    }
    
    /**
     * Vérifie si le jeu de caractères fourni est supporté
     *
     * @param string $in_charset Type mime recherché
     * @return integer qualité (1 <=> préféré, 0 <=> inconnu)
     */
    public function getCharsetQuality($in_charset) {
        $lc_charset = strtolower($in_charset);
        if (array_key_exists($lc_charset, $this->charset)) {
            return $this->charset[$lc_charset];
        } elseif (array_key_exists(self::CHARSET_ALL,$this->charset)) {
            return $this->charset[self::CHARSET_ALL];
        } else {
            return 0.0;
        }
    }
}
?>